package com.mt.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mt.mapper.OrderInfoMapper;
import com.mt.pojo.OrderInfo;
import com.mt.RedisUtils;
import com.mt.VO.FilmScheduleInfoVO;
import com.mt.constants.Result;
import com.mt.constants.SYS;
import com.mt.enums.Status;
import com.mt.enums.OrderStatus;
import com.mt.exception.GlobalException;
import com.mt.exception.OrderException;
import com.mt.feign.CinemaAdminApiProvider;
import com.mt.pojo.CinemaSeat;
import com.mt.pojo.Ticket;
import com.mt.service.OrderService;
import com.mt.utils.SnowFlakeGenerator;
import com.mt.utils.orderLockKeyGenerator;
import com.mt.vo.OrderListVO;
import com.mt.vo.PayOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Wang
 * @since 2020-12-28
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {

    @Resource
    OrderInfoMapper orderInfoMapper;
    @Resource
    RedisUtils redisUtils;
    @Resource
    CinemaAdminApiProvider cinemaAdminApiProvider;

    /**
     * 购买流程
     * 1. redis分布式锁判断
     * 2. 座位数据库修改
     * 3. 创建订单
     * 4. 释放锁, 等待用户请求支付接口后修改订单状态为完成
     * 跳转到支付订单界面
     */

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public PayOrderVO createOrder(String userId, int scheduleId, List<CinemaSeat> seats) {
        List<String> keys = orderLockKeyGenerator.getKey(scheduleId, seats);
        try {
            boolean lockStatus = false;
            for (String s : keys) {
                lockStatus = redisUtils.lock(s);
                if (!lockStatus) {
                    throw new OrderException(Status.TICKET_HAD_SOLD, s);
                }
            }
            //购票逻辑
            if (lockStatus) {
                //插入座位
                List<Ticket> existTicketList = orderInfoMapper.existTicket(scheduleId, seats);
                if (existTicketList == null || !existTicketList.isEmpty()) {
                    throw new OrderException(Status.TICKET_HAD_SOLD, "座位已售");
                }
                SnowFlakeGenerator generator = new SnowFlakeGenerator();
                long curOrderId = generator.nextId();
                boolean insertTickets =
                        orderInfoMapper.BatchInsertTicket(curOrderId,userId, scheduleId, seats);
                if (insertTickets) {
                    OrderInfo order = new OrderInfo();
                    order.setOrderId(curOrderId);
                    order.setScheduleId(scheduleId);
                    order.setUserId(userId);
                    //通过前端倒计时
                    order.setCreateTime(DateUtil.date());
                    order.setOrderStatus(OrderStatus.NOT_PAY.getCode());
                    Result result = cinemaAdminApiProvider.getScheduleDetailInfo(scheduleId);
                    if (result.getCode().equals(Status.SUCCESS.getCode())) {
                        log.info(JSONUtil.toJsonPrettyStr(result.getData()));
                        FilmScheduleInfoVO scheduleInfo =
                                JSONUtil.toBean(JSONUtil.toJsonPrettyStr(result.getData()), FilmScheduleInfoVO.class);
                        //计算金额, 获取用户信息, ? 后期可能添加一个优惠系统?
                        BigDecimal total = scheduleInfo.getPrice().multiply(BigDecimal.valueOf(seats.size()));
                        order.setPayment(total);
                        int insert = orderInfoMapper.insert(order);
                        //返回界面数据
                        if (insert>0){
                            PayOrderVO payOrderVO = new PayOrderVO();
                            payOrderVO.setOrderId(order.getOrderId().toString());
                            payOrderVO.setScheduleInfo(scheduleInfo);
                            payOrderVO.setPayment(order.getPayment());
                            payOrderVO.setSeatList(seats);
                            return payOrderVO;
                        }else {
                            throw new GlobalException(Status.CREATE_ORDER_ERROR);
                        }
//                        return order.getOrderId().toString();
                    } else {
                        //远程获取信息失败
                        throw new GlobalException(Status.ERROR, "系统繁忙,请重试");
                    }
                } else {
                    throw new OrderException(Status.CREATE_ORDER_ERROR);
                }
            } else {
                throw new OrderException(Status.TICKET_HAD_SOLD, "座位已售");
            }
        } catch (OrderException e) {
            log.error(e.toString());
            throw new GlobalException(e.getStatus());
        } catch (RuntimeException e) {
            //对异常进行处理
            log.error(e.toString());
            throw new GlobalException(Status.ERROR, "系统繁忙,请重试");
        } finally {
            //释放分布式锁
            for (String s : keys) {
                redisUtils.delete(SYS.LOCK_PREFIX + s);
                log.error("座位锁已删除" + SYS.LOCK_PREFIX + s);
            }
        }

    }

    @Override
    public Integer checkOrdersStatus(String orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(Wrappers.<OrderInfo>lambdaQuery().eq(OrderInfo::getOrderId, orderId));
        return  orderInfo.getOrderStatus();
    }

    /**
     * 支付订单后调用的API
     * 修改订单的支付状态
     */
    @Override
    public Boolean confirmPayOrder(String orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(Wrappers.<OrderInfo>lambdaQuery().eq(OrderInfo::getOrderId, orderId));
        if (orderInfo != null ){
            boolean confirmOrder = orderInfoMapper.confirmOrder(new Long(orderId));
            if (! confirmOrder ) {
                throw new GlobalException(Status.ERROR);
            }
        }else {
            throw new GlobalException(Status.ORDER_NOT_EXIST);
        }
        return true;
    }

    //todo 取消订单 退款
    @Override
    public Boolean cancelOrder(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(Wrappers.<OrderInfo>lambdaQuery().eq(OrderInfo::getOrderId, orderId));
         if (orderInfo.getOrderStatus().equals(OrderStatus.NOT_PAY)) {
             boolean cancel = orderInfoMapper.cancelOrderSeats(orderId);
             if (cancel) {
                 boolean cancelOrder = orderInfoMapper.cancelOrder(orderId);
                 return cancelOrder;
             } else {
                 throw new GlobalException(Status.ERROR, "系统错误");
             }
         }
         return true;
    }

    /**
     * 用户获取订单信息
     */
    @Override
    public List<OrderListVO> listOrderByUser(String userId) {
        List<OrderListVO> orderList = orderInfoMapper.listOrderByUser(userId);
        return orderList;
    }

    @Override
    public IPage<OrderListVO> pageOrderList(int currentPage, int pageSize, String filmName,int cinemaId) {
        IPage<OrderListVO> page = new Page<>(currentPage,pageSize);
        filmName = StrUtil.isBlank(filmName) ?null : "%"+filmName+"%";
        List<OrderListVO> orderListVOS = orderInfoMapper.pageOrder(page, filmName,cinemaId);
        page.setRecords(orderListVOS);
        return page;
    }


    /**
     * 获取订单详情
     */
    @Override
    public Ticket getOrderDetail(String orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(Wrappers.<OrderInfo>lambdaQuery().eq(OrderInfo::getOrderId, orderId));
        Ticket ticketOrderDetail = orderInfoMapper.getTicketOrderDetail(orderInfo.getScheduleId());
        //调用cinema服务接口 获取场次信息
        Result result = cinemaAdminApiProvider.getScheduleDetailInfo(orderInfo.getScheduleId());
        if (result.getCode().equals(Status.SUCCESS.getCode())) {
            ticketOrderDetail.setScheduleInfo((FilmScheduleInfoVO) result.getData());
        } else {
            //todo 待完善
            throw new GlobalException(Status.ERROR, "等待完善的逻辑");
        }
        return ticketOrderDetail;
    }

    /**
     * 电影票是否已被购买
     */
    @Override
    public boolean existTicket(int scheduleId, List<CinemaSeat> seatList) {
        //todo 校验购买时间是否超过许可时间,调用 电影场次的api
        if (seatList.isEmpty()) {
            throw new GlobalException(Status.PARAM_ERROR);
        }
        List<Ticket> existTicket = orderInfoMapper.existTicket(scheduleId, seatList);
        if (existTicket == null || !existTicket.isEmpty()) {
            throw new GlobalException(Status.TICKET_HAD_SOLD);
        }
        return false;
    }

    /**
     * 已购买电影票,返回的是座位id
     */
    @Override
    public List<Integer> getSoldTickets(int scheduleId) {
        List<Integer> soldTickets = orderInfoMapper.getSoldTickets(scheduleId);
        if (soldTickets == null || soldTickets.isEmpty()) {
            return CollUtil.newArrayList();
        }
        return soldTickets;
    }
}
